<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: huajie <banhuajie@163.com>
// +----------------------------------------------------------------------

namespace Admin\Model;
use Think\Model;
use Admin\Model\AuthGroupModel;

/**
 * 文檔基礎模型
 */
class DocumentModel extends Model{

    /* 自動驗證規則 */
    protected $_validate = array(
       // array('name', '/^[a-zA-Z]\w{0,39}$/', '文檔標識不合法', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
        array('name', 'checkName', '標識已經存在', self::VALUE_VALIDATE, 'callback', self::MODEL_BOTH),
        array('title', 'require', '標題不能為空', self::MUST_VALIDATE, 'regex', self::MODEL_BOTH),
        array('title', '1,80', '標題長度不能超過80個字符', self::MUST_VALIDATE, 'length', self::MODEL_BOTH),
    	array('level', '/^[\d]+$/', '優先級只能填正整數', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
        //TODO: 外鏈編輯驗證
        //array('link_id', 'url', '外鏈格式不正確', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
        array('description', '1,140', '簡介長度不能超過140個字符', self::VALUE_VALIDATE, 'length', self::MODEL_BOTH),
        array('category_id', 'require', '分類不能為空', self::MUST_VALIDATE , 'regex', self::MODEL_INSERT),
        array('category_id', 'require', '分類不能為空', self::EXISTS_VALIDATE , 'regex', self::MODEL_UPDATE),
        array('category_id', 'checkCategory', '該分類不允許發布內容', self::EXISTS_VALIDATE , 'callback', self::MODEL_UPDATE),
        array('model_id,category_id', 'checkModel', '該分類沒有綁定當前模型', self::MUST_VALIDATE , 'callback', self::MODEL_INSERT),
        array('deadline', '/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/', '日期格式不合法,請使用"年-月-日 時:分"格式,全部為數字', self::VALUE_VALIDATE  , 'regex', self::MODEL_BOTH),
        array('create_time', '/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/', '日期格式不合法,請使用"年-月-日 時:分"格式,全部為數字', self::VALUE_VALIDATE  , 'regex', self::MODEL_BOTH),
    );

    /* 自動完成規則 */
    protected $_auto = array(
        array('uid', 'is_login', self::MODEL_INSERT, 'function'),
        array('title', 'htmlspecialchars', self::MODEL_BOTH, 'function'),
        array('description', 'htmlspecialchars', self::MODEL_BOTH, 'function'),
    	array('root', 'getRoot', self::MODEL_BOTH, 'callback'),
        array('link_id', 'getLink', self::MODEL_BOTH, 'callback'),
        array('attach', 0, self::MODEL_INSERT),
        array('view', 0, self::MODEL_INSERT),
        array('comment', 0, self::MODEL_INSERT),
        array('extend', 0, self::MODEL_INSERT),
        array('create_time', 'getCreateTime', self::MODEL_BOTH,'callback'),
		array('reply_time', 'getCreateTime', self::MODEL_INSERT,'callback'),
        array('update_time', NOW_TIME, self::MODEL_BOTH),
        array('status', 'getStatus', self::MODEL_BOTH, 'callback'),
        array('position', 'getPosition', self::MODEL_BOTH, 'callback'),
        array('deadline', 'strtotime', self::MODEL_BOTH, 'function'),
        array('starttime', 'strtotime', self::MODEL_BOTH, 'function'), 
    );

    /**
     * 獲取文檔列表
     * @param  integer  $category 分類ID
     * @param  string   $order    排序規則
     * @param  integer  $status   狀態
     * @param  boolean  $count    是否返回總數
     * @param  string   $field    字段 true-所有字段
     * @param  string   $limit    分頁參數
     * @param  array    $map      查詢條件參數
     * @return array              文檔列表
     * @author huajie <banhuajie@163.com>
     */
    public function lists($category, $order = '`id` DESC', $status = 1, $field = true, $limit = '10', $map = array()){
        $map = array_merge($this->listMap($category, $status), $map);
        return $this->field($field)->where($map)->order($order)->limit($limit)->select();
    }

    /**
     * 計算列表總數
     * @param  number  $category 分類ID
     * @param  integer $status   狀態
     * @return integer           總數
     */
    public function listCount($category, $status = 1, $map = array()){
        $map = array_merge($this->listMap($category, $status), $map);
        return $this->where($map)->count('id');
    }

    /**
     * 獲取詳情頁數據
     * @param  integer $id 文檔ID
     * @return array       詳細數據
     */
    public function detail($id){
        /* 獲取基礎數據 */
        $info = $this->field(true)->find($id);
        if(!(is_array($info) || 1 !== $info['status'])){
            $this->error = '文檔被禁用或已刪除！';
            return false;
        }

        /* 獲取模型數據 */
        $logic  = $this->logic($info['model_id']);
        $detail = $logic->detail($id); //獲取指定ID的數據
        if(!$detail){
            $this->error = $logic->getError();
            return false;
        }
        $info = array_merge($info, $detail);

        return $info;
    }

    /**
     * 返回前壹篇文檔信息
     * @param  array $info 當前文檔信息
     * @return array
     */
    public function prev($info){
        $map = array(
            'id'          => array('lt', $info['id']),
            'category_id' => $info['category_id'],
            'status'      => 1,
        );

        /* 返回前壹條數據 */
        return $this->field(true)->where($map)->order('id DESC')->find();
    }

    /**
     * 獲取下壹篇文檔基本信息
     * @param  array    $info 當前文檔信息
     * @return array
     */
    public function next($info){
        $map = array(
            'id'          => array('gt', $info['id']),
            'category_id' => $info['category_id'],
            'status'      => 1,
        );

        /* 返回下壹條數據 */
        return $this->field(true)->where($map)->order('id')->find();
    }

    /**
     * 新增或更新壹個文檔
     * @param array  $data 手動傳入的數據
     * @return boolean fasle 失敗 ， int  成功 返回完整的數據
     * @author huajie <banhuajie@163.com>
     */
    public function update($data = null,$order =null){
    	/* 檢查文檔類型是否符合要求 */

    	$res = $this->checkDocumentType( I('type'), I('pid') );
    	if(!$res['status']){
    		$this->error = $res['info'];
    		return false;
    	}

        /* 獲取數據對象 */
        $data = $this->create($data);
        if(empty($data)){
            return false;
        }
       
        /* 添加或新增基礎內容 */
        if(empty($data['id'])){ //新增數據
            $id = $this->add($data); //添加基礎內容

            if(!$id){
                            
                $this->error = '新增基礎內容出錯！';
                return false;
            }
        } else { //更新數據
            $status = $this->save(); //更新基礎內容
            if(false === $status){
                $this->error = '更新基礎內容出錯！';
                return false;
            }
        }

        /* 添加或新增擴展內容 */
        $logic = $this->logic($data['model_id']);
     
        if(!$logic->update($id)){
            
            if(isset($id)){ //新增失敗，刪除基礎數據
                $this->delete($id);
            }
            $this->error = $logic->getError();
            return false;
        }

        hook('documentSaveComplete', array('model_id'=>$data['model_id']));

        //行為記錄
        if($id){
        	action_log('add_document', 'document', $id, UID);
        }
        if(isset($order))
        {
        $map2['address'] = $order;    
        M('Document_course')->where(array('id'=>$id))->save($map2); 
        }
        //內容添加或更新完成
        return $data;
    }

    /**
     * 獲取段落列表
     * @param  integer $id    文檔ID
     * @param  integer $page  顯示頁碼
     * @param  boolean $field 查詢字段
     * @param  boolean $logic 是否查詢模型數據
     * @return array
     */
    public function part($id, $page = 1, $field = true, $logic = true){
        $map  = array('status' => 1, 'type' => 3, 'pid' => $id);
        $info = $this->field($field)->where($map)->page($page, 10)->order('id')->select();
        if(!$info) {
            $this->error = '該文檔沒有段落！';
            return false;
        }

        /* 不獲取段落詳情 */
        if(!$logic){
            return $info;
        }

        /* 獲取段落詳情 */
        $model = $logic = array();
        foreach ($info as $value) {
            $model[$value['model_id']][] = $value['id'];
        }
        foreach ($model as $model_id => $ids) {
            $data   = $this->logic($model_id)->lists($ids);
            $logic += $data;
        }

        /* 合並數據 */
        foreach ($info as &$value) {
            $value = array_merge($value, $logic[$value['id']]);
        }

        return $info;
    }

    /**
     * 獲取指定文檔的段落總數
     * @param  number $id 段落ID
     * @return number     總數
     */
    public function partCount($id){
        $map = array('status' => 1, 'type' => 3, 'pid' => $id);
        return $this->where($map)->count('id');
    }

    /**
     * 獲取推薦位數據列表
     * @param  number  $pos      推薦位 1-列表推薦，2-頻道頁推薦，4-首頁推薦
     * @param  number  $category 分類ID
     * @param  number  $limit    列表行數
     * @param  boolean $filed    查詢字段
     * @return array             數據列表
     */
    public function position($pos, $category = null, $limit = null, $field = true){
        $map = $this->listMap($category, 1, $pos);

        /* 設置列表數量 */
        is_numeric($limit) && $this->limit($limit);

        /* 讀取數據 */
        return $this->field($field)->where($map)->select();
    }

    /**
     * 獲取數據狀態
     * @return integer 數據狀態
     */
    protected function getStatus(){
    	$id = I('post.id');
        $cate = I('post.category_id');
        if(empty($id)){	//新增
        	$status = 1;
        }else{				//更新
			$status = $this->getFieldById($id, 'status');
			//編輯草稿改變狀態
			if($status == 3){
				$status = 1;
			}
        }
        return $status;
    }

    /**
     * 獲取根節點id
     * @return integer 數據id
     * @author huajie <banhuajie@163.com>
     */
    protected function getRoot(){
    	$pid = I('post.pid');
    	if($pid == 0){
    		return 0;
    	}
    	$p_root = $this->getFieldById($pid, 'root');
    	return $p_root == 0 ? $pid : $p_root;
    }

    /**
     * 創建時間不寫則取當前時間
     * @return int 時間戳
     * @author huajie <banhuajie@163.com>
     */
    protected function getCreateTime(){
        $create_time    =   I('post.create_time');
        return $create_time?strtotime($create_time):NOW_TIME;
    }

    /**
     * 驗證分類是否允許發布內容
     * @param  integer $id 分類ID
     * @return boolean     true-允許發布內容，false-不允許發布內容
     */
    public function checkCategory($id){
        $publish = get_category($id, 'allow_publish');
        return $publish ? true : false;
    }

    /**
     * 檢測分類是否綁定了指定模型
     * @param  array $info 模型ID和分類ID數組
     * @return boolean     true-綁定了模型，false-未綁定模型
     */
    protected function checkModel($info){
        $model = get_category($info['category_id'], 'model');
        return in_array($info['model_id'], $model);
    }

    /**
     * 獲取擴展模型對象
     * @param  integer $model 模型編號
     * @return object         模型對象
     */
    private function logic($model){
        return D(get_document_model($model, 'name'), 'Logic');
    }

    /**
     * 設置where查詢條件
     * @param  number  $category 分類ID
     * @param  number  $pos      推薦位
     * @param  integer $status   狀態
     * @return array             查詢條件
     */
    private function listMap($category, $status = 1, $pos = null){
        /* 設置狀態 */
        $map = array('status' => $status);

        /* 設置分類 */
        if(!is_null($category)){
            if(is_numeric($category)){
                $map['category_id'] = $category;
            } else {
                $map['category_id'] = array('in', str2arr($category));
            }
        }

        /* 設置推薦位 */
        if(is_numeric($pos)){
            $map[] = "position & {$pos} = {$pos}";
        }

        return $map;
    }

    /**
     * 檢查標識是否已存在(只需在同壹根節點下不重復)
     * @param string $name
     * @return true無重復，false已存在
     * @author huajie <banhuajie@163.com>
     */
    protected function checkName(){
        $name = I('post.name');
        $pid = I('post.pid', 0);
        $id = I('post.id', 0);

        //獲取根節點
        if($pid == 0){
        	$root = 0;
        }else{
        	$root = $this->getFieldById($pid, 'root');
        	$root = $root == 0 ? $pid : $root;
        }

        $map = array('root'=>$root, 'name'=>$name, 'id'=>array('neq',$id));
        $res = $this->where($map)->getField('id');
        if($res){
        	return false;
        }
        return true;
    }

    /**
     * 生成不重復的name標識
     * @author huajie <banhuajie@163.com>
     */
    private function generateName(){
        $str = 'abcdefghijklmnopqrstuvwxyz0123456789';	//源字符串
        $min = 10;
        $max = 39;
        $name = false;
        while (true){
            $length = rand($min, $max);	//生成的標識長度
            $name = substr(str_shuffle(substr($str,0,26)), 0, 1);	//第壹個字母
            $name .= substr(str_shuffle($str), 0, $length);
            //檢查是否已存在
            $res = $this->getFieldByName($name, 'id');
            if(!$res){
                break;
            }
        }
        return $name;
    }

    /**
     * 生成推薦位的值
     * @return number 推薦位
     * @author huajie <banhuajie@163.com>
     */
    protected function getPosition(){
        $position = I('post.position');
        if(!is_array($position)){
            return 0;
        }else{
            $pos = 0;
            foreach ($position as $key=>$value){
                $pos += $value;		//將各個推薦位的值相加
            }
            return $pos;
        }
    }


    /**
     * 刪除狀態為-1的數據（包含擴展模型）
     * @return true 刪除成功， false 刪除失敗
     * @author huajie <banhuajie@163.com>
     */
    public function remove(){
        //查詢假刪除的基礎數據
        if ( is_administrator() ) {
            $map = array('status'=>-1);
        }else{
            $cate_ids = AuthGroupModel::getAuthCategories(UID);
            $map = array('status'=>-1,'category_id'=>array( 'IN',trim(implode(',',$cate_ids),',') ));
        }
        $base_list = $this->where($map)->field('id,model_id')->select();
        //刪除擴展模型數據
        $base_ids = array_column($base_list,'id');
        //孤兒數據
        $orphan   = get_stemma( $base_ids,$this, 'id,model_id');

        $all_list  = array_merge( $base_list,$orphan );
        foreach ($all_list as $key=>$value){
            $logic = $this->logic($value['model_id']);
            $logic->delete($value['id']);
        }

        //刪除基礎數據
        $ids = array_merge( $base_ids, (array)array_column($orphan,'id') );
        if(!empty($ids)){
        	$res = $this->where( array( 'id'=>array( 'IN',trim(implode(',',$ids),',') ) ) )->delete();
        }

        return $res;
    }

    /**
     * 獲取鏈接id
     * @return int 鏈接對應的id
     * @author huajie <banhuajie@163.com>
     */
    protected function getLink(){
        $link = I('post.link_id');
        if(empty($link)){
            return 0;
        } else if(is_numeric($link)){
            return $link;
        }
        $res = D('Url')->update(array('url'=>$link));
        return $res['id'];
    }

    /**
     * 保存為草稿
     * @return array 完整的數據， false 保存出錯
     * @author huajie <banhuajie@163.com>
     */
    public function autoSave(){
        $post = I('post.');

        /* 檢查文檔類型是否符合要求 */
        $res = $this->checkDocumentType( I('type'), I('pid') );
        if(!$res['status']){
        	$this->error = $res['info'];
        	return false;
        }

        //觸發自動保存的字段
        $save_list = array('name','title','description','position','link_id','cover_id','deadline','create_time','content');
        foreach ($save_list as $value){
            if(!empty($post[$value])){
                $if_save = true;
                break;
            }
        }

        if(!$if_save){
            $this->error = '您未填寫任何內容';
            return false;
        }

        //重置自動驗證
        $this->_validate = array(
            array('name', '/^[a-zA-Z]\w{0,39}$/', '文檔標識不合法', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
            array('name', '', '標識已經存在', self::VALUE_VALIDATE, 'unique', self::MODEL_BOTH),
            array('title', '1,80', '標題長度不能超過80個字符', self::VALUE_VALIDATE, 'length', self::MODEL_BOTH),
            array('description', '1,140', '簡介長度不能超過140個字符', self::VALUE_VALIDATE, 'length', self::MODEL_BOTH),
            array('category_id', 'require', '分類不能為空', self::MUST_VALIDATE , 'regex', self::MODEL_BOTH),
            array('category_id', 'checkCategory', '該分類不允許發布內容', self::EXISTS_VALIDATE , 'callback', self::MODEL_UPDATE),
            array('model_id,category_id', 'checkModel', '該分類沒有綁定當前模型', self::MUST_VALIDATE , 'callback', self::MODEL_INSERT),
            array('deadline', '/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/', '日期格式不合法,請使用"年-月-日 時:分"格式,全部為數字', self::VALUE_VALIDATE  , 'regex', self::MODEL_BOTH),
            array('create_time', '/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/', '日期格式不合法,請使用"年-月-日 時:分"格式,全部為數字', self::VALUE_VALIDATE  , 'regex', self::MODEL_BOTH),
        );
        $this->_auto[] = array('status', '3', self::MODEL_BOTH);

        if(!($data = $this->create())){
            return false;
        }

        /* 添加或新增基礎內容 */
        if(empty($data['id'])){ //新增數據
            $id = $this->add(); //添加基礎內容

            if(!$id){
    			$this->error = '新增基礎內容出錯！';
                return false;
            }
            $data['id'] = $id;
        } else { //更新數據
            $status = $this->save(); //更新基礎內容
            if(false === $status){
    			$this->error = '更新基礎內容出錯！';
                return false;
            }
        }

        /* 添加或新增擴展內容 */
        $logic = $this->logic($data['model_id']);
        if(!$logic->autoSave($id)){
            if(isset($id)){ //新增失敗，刪除基礎數據
                $this->delete($id);
            }
            $this->error = $logic->getError();
            return false;
        }

        //內容添加或更新完成
        return $data;
    }

    /**
     * 獲取目錄列表
     * @param intger $pid 目錄的根節點
     * @return boolean
     * @author huajie <banhuajie@163.com>
     */
    public function getDirectoryList($pid = null){
    	if(empty($pid)){
    		return false;
    	}
    	$tree = S('sys_directory_tree');
		if(empty($tree)){
			$res = $this->getChild($pid);
			S('sys_directory_tree', $tree);
		}
		return $res;
    }

    /**
     * 遞歸查詢子文檔
     * @param intger $pid
     * @return array: 子文檔數組
     * @author huajie <banhuajie@163.com>
     */
    private function getChild($pid){
    	$tree = array();
    	$map = array('status'=>1,'type'=>1);
    	if(is_array($pid)){
    		$map['pid'] = array('in', implode(',', $pid));
    	}else{
    		$map['pid'] = $pid;
    	}
    	$child = $this->where($map)->field('id,name,title,pid')->order('level DESC,id DESC')->select();
    	if(!empty($child)){
    		foreach ($child as $key=>$value){
    			$pids[] = $value['id'];
    		}
    		$tree = array_merge($child, $this->getChild($pids));
    	}
    	return $tree;
    }

    /**
     * 檢查指定文檔下面子文檔的類型
     * @param intger $type 子文檔類型
     * @param intger $pid 父文檔類型
     * @return array 鍵值：status=>是否允許（0,1），'info'=>提示信息
     * @author huajie <banhuajie@163.com>
     */
    public function checkDocumentType($type = null, $pid = null){
    	$res = array('status'=>1, 'info'=>'');
		if(empty($type)){
			return array('status'=>0, 'info'=>'文檔類型不能為空');
		}
		if(empty($pid)){
			return $res;
		}
		//查詢父文檔的類型
		if(is_numeric($pid)){
			$ptype = $this->getFieldById($pid, 'type');
		}else{
			$ptype = $this->getFieldByName($pid, 'type');
		}
		//父文檔為目錄時
		if($ptype == 1){
			return $res;
		}
		//父文檔為主題時
		if($ptype == 2){
			if($type != 3){
				return array('status'=>0, 'info'=>'主題下面只允許添加段落');
			}else{
				return $res;
			}
		}
		//父文檔為段落時
		if($ptype == 3){
			return array('status'=>0, 'info'=>'段落下面不允許再添加子內容');
		}
		return array('status'=>0, 'info'=>'父文檔類型不正確');
    }

    /**
     * 分頁
     * @param type $category
     * @param type $pages
     * @param type $status
     * @return type
     */
    
    public function listpage($category,$pages=8,$status=1){
                
                $map = array('category_id'=>$category,'status'=>$status);
                $count = $this->where($map)->count();//获取符合条件的数据总数count
                $page=new \Think\Page($count, $pages);
                $list=$this->where($map)->order('update_time desc')->limit($page->firstRow.','.$page->listRows)->select();
                $page->setConfig('prev', "上一页");//上一页
                $page->setConfig('next', '下一页');//下一页
                $page->setConfig('first', '<<');//第一页
                $page->setConfig('last', '>>');//最后一页
                $page->setConfig( 'theme','%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END% %HEADER%');
                $data=array(
                'data1'=>$page->show(),
                'data2'=>$list,
                );
                $arr = array();
                foreach($data['data2'] as $val)
                {
                $arr[] = $this->detail($val['id']);
                }
                $data['data2'] = $arr;
                return  $data;
                }
    
}